﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading;
using Common;
using DO.Workflows;
using Microsoft.Practices.EnterpriseLibrary.Data;

namespace DAL.Workflows
{
    public class JobDALC
    {
        #region job
        public static void AddJob(Job job)
        {
            Database db = DatabaseFactory.CreateDatabase("Workflow");
            db.ExecuteNonQuery("JobInsert",
                               job.JobID,
                               job.RunID,
                               job.ComponentID,
                               StringUtil.ToString(job.Dependencies),
                               job.IsFirstJob,
                               job.IsLastJob,
                               job.HasError,
                               job.Cancelled,
                               (int)job.Priority,
                               job.SubmissionTime,
                               job.ReceiveTime,
                               job.StartTime,
                               job.FinishTime);
        }

        public static Job GetJob(Guid jobID)
        {
            Job job = null;
            Database db = DatabaseFactory.CreateDatabase("Workflow");
            IDataReader reader = db.ExecuteReader("JobGet", jobID);
            while (reader.Read())
            {
                Guid runID = new Guid(reader["RunID"].ToString());
                Guid componentID = new Guid(reader["ComponentID"].ToString());
                string[] dependencyIDs =
                    StringUtil.Split(reader["Dependency"] == DBNull.Value
                                         ? string.Empty
                                         : reader["Dependency"].ToString());
                List<Guid> dependencies = new List<Guid>();
                if (dependencyIDs != null && dependencyIDs.Length > 0)
                {
                    foreach (string dependentID in dependencyIDs)
                    {
                        Guid dependentGuid = new Guid(dependentID);
                        if (!dependencies.Contains(dependentGuid))
                            dependencies.Add(dependentGuid);
                    }
                }
                bool hasError = bool.Parse(reader["HasError"].ToString());
                bool isFirst = bool.Parse(reader["IsFirstJob"].ToString());
                bool isLast = bool.Parse(reader["IsLastJob"].ToString());
                bool cancelled = bool.Parse(reader["Cancelled"].ToString());
                ThreadPriority priority = (ThreadPriority)int.Parse(reader["Priority"].ToString());
                DateTime? receiveTime = reader["ReceiveTime"] == DBNull.Value
                                            ? new DateTime?()
                                            : DateTime.Parse(reader["ReceiveTime"].ToString());
                DateTime? submissionTime = reader["SubmitTime"] == DBNull.Value
                                            ? new DateTime?()
                                            : DateTime.Parse(reader["SubmitTime"].ToString());
                DateTime? startTime = reader["StartTime"] == DBNull.Value
                                            ? new DateTime?()
                                            : DateTime.Parse(reader["StartTime"].ToString());
                DateTime? finishTime = reader["FinishTime"] == DBNull.Value
                                            ? new DateTime?()
                                            : DateTime.Parse(reader["FinishTime"].ToString());
                job = new Job
                {
                    JobID = jobID,
                    RunID = runID,
                    ComponentID = componentID,
                    HasError = hasError,
                    Cancelled = cancelled,
                    IsFirstJob = isFirst,
                    IsLastJob = isLast,
                    Priority = priority,
                    ReceiveTime = receiveTime,
                    SubmissionTime = submissionTime,
                    StartTime = startTime,
                    FinishTime = finishTime
                };
            }
            reader.Close();
            return job;
        }

        public static Job GetJobByComponent(Guid componentID, Guid runID)
        {
            Job job = null;
            Database db = DatabaseFactory.CreateDatabase("Workflow");
            IDataReader reader = db.ExecuteReader("JobGeByComponent", componentID, runID);
            while (reader.Read())
            {
                Guid jobID=new Guid(reader["JobID"].ToString());
                string[] dependencyIDs =
                    StringUtil.Split(reader["Dependency"] == DBNull.Value
                                         ? string.Empty
                                         : reader["Dependency"].ToString());
                List<Guid> dependencies = new List<Guid>();
                if (dependencyIDs != null && dependencyIDs.Length > 0)
                {
                    foreach (string dependentID in dependencyIDs)
                    {
                        Guid dependentGuid = new Guid(dependentID);
                        if (!dependencies.Contains(dependentGuid))
                            dependencies.Add(dependentGuid);
                    }
                }
                bool hasError = bool.Parse(reader["HasError"].ToString());
                bool isFirst = bool.Parse(reader["IsFirstJob"].ToString());
                bool isLast = bool.Parse(reader["IsLastJob"].ToString());
                bool cancelled = bool.Parse(reader["Cancelled"].ToString());
                ThreadPriority priority = (ThreadPriority)int.Parse(reader["Priority"].ToString());
                DateTime? receiveTime = reader["ReceiveTime"] == DBNull.Value
                                            ? new DateTime?()
                                            : DateTime.Parse(reader["ReceiveTime"].ToString());
                DateTime? submissionTime = reader["SubmitTime"] == DBNull.Value
                                            ? new DateTime?()
                                            : DateTime.Parse(reader["SubmitTime"].ToString());
                DateTime? startTime = reader["StartTime"] == DBNull.Value
                                            ? new DateTime?()
                                            : DateTime.Parse(reader["StartTime"].ToString());
                DateTime? finishTime = reader["FinishTime"] == DBNull.Value
                                            ? new DateTime?()
                                            : DateTime.Parse(reader["FinishTime"].ToString());
                job = new Job
                {
                    JobID = jobID,
                    RunID = runID,
                    ComponentID = componentID,
                    HasError = hasError,
                    Cancelled = cancelled,
                    IsFirstJob = isFirst,
                    IsLastJob = isLast,
                    Priority = priority,
                    ReceiveTime = receiveTime,
                    SubmissionTime = submissionTime,
                    StartTime = startTime,
                    FinishTime = finishTime
                };
            }
            reader.Close();
            return job;
        }

        public static void SaveJob(Job job)
        {
            Database db = DatabaseFactory.CreateDatabase("Workflow");
            db.ExecuteNonQuery("JobUpdate",
                               job.JobID,
                               job.RunID,
                               job.ComponentID,
                               StringUtil.ToString(job.Dependencies),
                               job.IsFirstJob,
                               job.IsLastJob,
                               job.HasError,
                               job.Cancelled,
                               (int)job.Priority,
                               job.SubmissionTime,
                               job.ReceiveTime,
                               job.StartTime,
                               job.FinishTime);
        }

        public static List<Job> GetAllQueuedJobs()
        {
            List<Job> jobs = new List<Job>();
            Database db = DatabaseFactory.CreateDatabase("Workflow");
            IDataReader reader = db.ExecuteReader("JobsGetAllQueued");
            while (reader.Read())
            {
                Guid jobID = new Guid(reader["JobID"].ToString());
                Guid runID=new Guid(reader["RunID"].ToString());
                Guid componentID = new Guid(reader["ComponentID"].ToString());
                string[] dependencyIDs =
                    StringUtil.Split(reader["Dependency"] == DBNull.Value
                                         ? string.Empty
                                         : reader["Dependency"].ToString());
                List<Guid> dependencies = new List<Guid>();
                if (dependencyIDs != null && dependencyIDs.Length > 0)
                {
                    foreach (string dependentID in dependencyIDs)
                    {
                        Guid dependentGuid = new Guid(dependentID);
                        if (!dependencies.Contains(dependentGuid))
                            dependencies.Add(dependentGuid);
                    }
                }
                bool hasError = bool.Parse(reader["HasError"].ToString());
                bool isFirst = bool.Parse(reader["IsFirstJob"].ToString());
                bool isLast = bool.Parse(reader["IsLastJob"].ToString());
                bool cancelled = bool.Parse(reader["Cancelled"].ToString());
                ThreadPriority priority = (ThreadPriority)int.Parse(reader["Priority"].ToString());
                DateTime? receiveTime = reader["ReceiveTime"] == DBNull.Value
                                            ? new DateTime?()
                                            : DateTime.Parse(reader["ReceiveTime"].ToString());
                DateTime? submissionTime = reader["SubmitTime"] == DBNull.Value
                                            ? new DateTime?()
                                            : DateTime.Parse(reader["SubmitTime"].ToString());
                DateTime? startTime = reader["StartTime"] == DBNull.Value
                                            ? new DateTime?()
                                            : DateTime.Parse(reader["StartTime"].ToString());
                DateTime? finishTime = reader["FinishTime"] == DBNull.Value
                                            ? new DateTime?()
                                            : DateTime.Parse(reader["FinishTime"].ToString());
                Job job = new Job
                {
                    JobID = jobID,
                    RunID = runID,
                    ComponentID = componentID,
                    HasError = hasError,
                    Cancelled = cancelled,
                    IsFirstJob = isFirst,
                    IsLastJob = isLast,
                    Priority = priority,
                    ReceiveTime = receiveTime,
                    SubmissionTime = submissionTime,
                    StartTime = startTime,
                    FinishTime = finishTime
                };
                jobs.Add(job);
            }
            reader.Close();
            return jobs;
        }

        public static List<Job> GetJobsByRun(Guid runID)
        {
            List<Job> jobStatuses = new List<Job>();
            Database db = DatabaseFactory.CreateDatabase("Workflow");
            IDataReader reader = db.ExecuteReader("JobGetByRun", runID);
            while (reader.Read())
            {
                Guid jobID = new Guid(reader["JobID"].ToString());
                Guid componentID = new Guid(reader["ComponentID"].ToString());
                string[] dependencyIDs =
                    StringUtil.Split(reader["Dependency"] == DBNull.Value
                                         ? string.Empty
                                         : reader["Dependency"].ToString());
                List<Guid> dependencies = new List<Guid>();
                if (dependencyIDs != null && dependencyIDs.Length > 0)
                {
                    foreach (string dependentID in dependencyIDs)
                    {
                        Guid dependentGuid = new Guid(dependentID);
                        if (!dependencies.Contains(dependentGuid))
                            dependencies.Add(dependentGuid);
                    }
                }
                bool hasError = bool.Parse(reader["HasError"].ToString());
                bool isFirst = bool.Parse(reader["IsFirstJob"].ToString());
                bool isLast = bool.Parse(reader["IsLastJob"].ToString());
                bool cancelled = bool.Parse(reader["Cancelled"].ToString());
                ThreadPriority priority = (ThreadPriority)int.Parse(reader["Priority"].ToString());
                DateTime? receiveTime = reader["ReceiveTime"] == DBNull.Value
                                            ? new DateTime?()
                                            : DateTime.Parse(reader["ReceiveTime"].ToString());
                DateTime? submissionTime = reader["SubmitTime"] == DBNull.Value
                                            ? new DateTime?()
                                            : DateTime.Parse(reader["SubmitTime"].ToString());
                DateTime? startTime = reader["StartTime"] == DBNull.Value
                                            ? new DateTime?()
                                            : DateTime.Parse(reader["StartTime"].ToString());
                DateTime? finishTime = reader["FinishTime"] == DBNull.Value
                                            ? new DateTime?()
                                            : DateTime.Parse(reader["FinishTime"].ToString());
                Job job = new Job
                {
                    JobID = jobID,
                    RunID = runID,
                    ComponentID = componentID,
                    HasError = hasError,
                    Cancelled = cancelled,
                    IsFirstJob = isFirst,
                    IsLastJob = isLast,
                    Priority = priority,
                    ReceiveTime = receiveTime,
                    SubmissionTime = submissionTime,
                    StartTime = startTime,
                    FinishTime = finishTime
                };
                jobStatuses.Add(job);
            }
            reader.Close();
            return jobStatuses;
        }

        public static void ReceiveJob(Guid jobID, DateTime? receiveTime, string machineName, string identityName)
        {
            Database db = DatabaseFactory.CreateDatabase("Workflow");
            db.ExecuteNonQuery("JobCheckout",
                               jobID,
                               receiveTime,
                               machineName,
                               identityName);
        }

        public static void SubmitJob(Guid jobID, DateTime? submitTime, string machineName, string identityName)
        {
            Database db = DatabaseFactory.CreateDatabase("Workflow");
            db.ExecuteNonQuery("JobSubmit",
                               jobID,
                               submitTime,
                               machineName,
                               identityName);
        }

        public static void DisableJob(Guid jobID)
        {
            Database db = DatabaseFactory.CreateDatabase("Workflow");
            db.ExecuteNonQuery("JobCancel", jobID);
        }

        public static bool AreUpstreamJobsDone(Job job)
        {
            if (job.Dependencies==null || job.Dependencies.Count==0)
                return true;
            List<Guid> finishedJobIDsForRun = JobDALC.GetFinishedJobs(job.RunID);
            int countFinished = 0;
            if(finishedJobIDsForRun !=null && finishedJobIDsForRun.Count>0)
            {
                foreach(Guid finishedJobID in finishedJobIDsForRun)
                {
                    if (job.Dependencies.Contains(finishedJobID))
                        countFinished++;
                }
            }
            if(countFinished==job.Dependencies.Count)
                return true;
            else
                return false;
        }

        public static List<Guid> GetFinishedJobs(Guid runID)
        {
            Database db = DatabaseFactory.CreateDatabase("Workflow");
            IDataReader reader = db.ExecuteReader("JobsGetFinished", runID);
            List<Guid> finishedJobIDs=new List<Guid>();
            while(reader.Read())
            {
                Guid jobID=new Guid(reader["JobID"].ToString());
                if(!finishedJobIDs.Contains(jobID))
                {
                    finishedJobIDs.Add(jobID);
                }
            }
            reader.Close();
            return finishedJobIDs;
        }
        #endregion

        #region instruction
        public static void SaveJobInstruction(InstructionBase instruction)
        {
            Database db = DatabaseFactory.CreateDatabase("Workflow");
            db.ExecuteNonQuery("InstructionInsert",
                               instruction.JobTicketID,
                               instruction.ComponentID,
                               instruction.Serialize().ToString());
        }

        public static string GetJobInstructionByJob(Guid jobID)
        {
            string xml = null;
            Database db = DatabaseFactory.CreateDatabase("Workflow");
            IDataReader reader = db.ExecuteReader("InstructionGet", jobID);
            if(reader.Read())
            {
                xml = reader["Data"].ToString();
            }
            reader.Close();
            return xml;
        }
        #endregion

        #region output
        public static void SaveJobOutput(ResultBase output)
        {
            Database db = DatabaseFactory.CreateDatabase("Workflow");
            db.ExecuteNonQuery("OutputInsert",
                               output.JobID,
                               output.ComponentID,
                               output.Serialize().ToString());
        }

        public static string GetJobOutputByJob(Guid jobID)
        {
            string xml = null;
            Database db = DatabaseFactory.CreateDatabase("Workflow");
            IDataReader reader = db.ExecuteReader("OutputGet", jobID);
            if (reader.Read())
            {
                xml = reader["Data"].ToString();
            }
            reader.Close();
            return xml;
        }
        #endregion
    }
}
